/**
 * Copyright (c) 2006 Amgad S Youssef
 * All Rights Reserved.
 * Licensed under the Eclipse Public License - v 1.0
 * For more information see http://www.eclipse.org/legal/epl-v10.html
 */
package org.eclipsejcde.wizards.jcapplet.pages;

import java.util.ArrayList;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaConventions;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.wizards.NewClassWizardPage;
import org.eclipse.jdt.ui.wizards.NewInterfaceWizardPage;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.DialogPage;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipsejcde.core.JCDECore;

/**
 * @author Amgad S Youssef
 *
 */
public class NewJCAppletExtraFeaturesWizardPage extends WizardPage {
	protected NewJCAppletWizardPage newJCAppletWizardPage;

	private Button supportsRMI;

	private Label riNameLabel;

	private Text riName;

	private Label riImplNameLabel;

	private Text riImplName;

	private Button generateRMISampleCode;

	private Button supportsSI;

	private Button serverApplet;

	private Button clientApplet;

	private Label siNameLabel;

	private Text siName;

	private Label siImplNameLabel;

	private Text siImplName;

	private Button generateSISampleCode;

	protected IType createdRIType;

	protected IType createdRIImplType;

	protected IType createdSIType;

	protected IType createdSIImplType;

	protected ExtraFeaturesBean bean;

	public boolean isClientApplet() {
		return clientApplet.getSelection();
	}

	public void setClientApplet(boolean clientApplet) {
		this.clientApplet.setSelection(clientApplet);
	}

	public String getRiImplName() {
		return riImplName.getText();
	}

	public void setRiImplName(String riImplName) {
		this.riImplName.setText(riImplName);
	}

	public String getRiName() {
		return riName.getText();
	}

	public void setRiName(String riName) {
		this.riName.setText(riName);
	}

	public boolean isServerApplet() {
		return serverApplet.getSelection();
	}

	public void setServerApplet(boolean serverApplet) {
		this.serverApplet.setSelection(serverApplet);
	}

	public String getSiImplName() {
		return siImplName.getText();
	}

	public void setSiImplName(String siImplName) {
		this.siImplName.setText(siImplName);
	}

	public String getSiName() {
		return siName.getText();
	}

	public void setSiName(String siName) {
		this.siName.setText(siName);
	}

	public boolean isSupportsRMI() {
		return supportsRMI.getSelection();
	}

	public void setSupportsRMI(boolean supportsRMI) {
		this.supportsRMI.setSelection(supportsRMI);
	}

	public boolean isSupportsSI() {
		return supportsSI.getSelection();
	}

	public void setSupportsSI(boolean supportsSI) {
		this.supportsSI.setSelection(supportsSI);
	}

	public boolean isGenerateRMISampleCode() {
		return generateRMISampleCode.getSelection();
	}

	public void setGenerateRMISampleCode(boolean generateRMISampleCode) {
		this.generateRMISampleCode.setSelection(generateRMISampleCode);
	}

	public boolean isGenerateSISampleCode() {
		return generateSISampleCode.getSelection();
	}

	public void setGenerateSISampleCode(boolean generateSISampleCode) {
		this.generateSISampleCode.setSelection(generateSISampleCode);
	}

	public IType getCreatedRIImplType() {
		return createdRIImplType;
	}

	public IType getCreatedRIType() {
		return createdRIType;
	}

	public IType getCreatedSIImplType() {
		return createdSIImplType;
	}

	public IType getCreatedSIType() {
		return createdSIType;
	}

	public NewJCAppletExtraFeaturesWizardPage(NewJCAppletWizardPage newJCAppletWizardPage) {
		super("org.eclipsejcde.wizards.jcapplet.pages.NewJCAppletExtraFeaturesWizardPage");
		this.newJCAppletWizardPage = newJCAppletWizardPage;
		setTitle("Extra Features");
		setDescription("Generate code for the below selected features.");
	}

	@Override
	public void createControl(Composite parent) {
		Composite composite = new Composite(parent, SWT.NONE);
		composite.setFont(parent.getFont());

		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		layout.marginHeight = 10;
		layout.verticalSpacing = 10;
		composite.setLayout(layout);

		GridData span1 = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1);

		GridData span2 = new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1);

		// Supports RMI section
		// checkbox
		supportsRMI = new Button(composite, SWT.CHECK);
		supportsRMI.setText("Supports Java Card RMI");
		supportsRMI.setLayoutData(span2);
		supportsRMI.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				supportsRMISelected(e);
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				supportsRMISelected(e);
			}
		});

		// label
		riNameLabel = new Label(composite, SWT.LEFT);
		riNameLabel.setText("Remote interface name:");
		riNameLabel.setEnabled(false);

		// text
		riName = new Text(composite, SWT.BORDER | SWT.SINGLE);
		riName.setEnabled(false);
		riName.setLayoutData(span1);
		riName.addModifyListener(new ModifyListener() {
			@Override
			public void modifyText(ModifyEvent e) {
				validatePage();
			}
		});

		// label
		riImplNameLabel = new Label(composite, SWT.LEFT);
		riImplNameLabel.setText("Remote interface implementer name:");
		riImplNameLabel.setEnabled(false);

		// text
		riImplName = new Text(composite, SWT.BORDER | SWT.SINGLE);
		riImplName.setEnabled(false);
		riImplName.setLayoutData(span1);
		riImplName.addModifyListener(new ModifyListener() {
			@Override
			public void modifyText(ModifyEvent e) {
				validatePage();
			}
		});

		// place holder
		new Label(composite, SWT.LEFT).setLayoutData(span1);

		// checkbox
		generateRMISampleCode = new Button(composite, SWT.CHECK);
		generateRMISampleCode.setText("Generate sample code");
		generateRMISampleCode.setLayoutData(span1);
		generateRMISampleCode.setEnabled(false);
		generateRMISampleCode.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				generateRMISampleCodeSelected(e);
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				generateRMISampleCodeSelected(e);
			}
		});

		// separator
		new Label(composite, SWT.HORIZONTAL | SWT.SEPARATOR).setLayoutData(span2);

		// Supports SI section
		supportsSI = new Button(composite, SWT.CHECK);
		supportsSI.setText("Supports Shareable Interfaces");
		supportsSI.setLayoutData(span2);
		supportsSI.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				supportsSISelected(e);
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				supportsSISelected(e);
			}
		});

		GridLayout siOptionsLayout = new GridLayout();
		siOptionsLayout.numColumns = 4;
		siOptionsLayout.marginHeight = 0;

		// radio buttons container
		Composite siOptionsComposite = new Composite(composite, SWT.NONE);
		siOptionsComposite.setFont(composite.getFont());
		siOptionsComposite.setLayout(siOptionsLayout);
		siOptionsComposite.setLayoutData(span2);

		// radiobutton
		serverApplet = new Button(siOptionsComposite, SWT.RADIO);
		serverApplet.setText("Server Applet");
		serverApplet.setSelection(true);
		serverApplet.setEnabled(false);
		serverApplet.setLayoutData(span1);
		serverApplet.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				serverClientSelected(e);
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				serverClientSelected(e);
			}
		});

		// radiobutton
		clientApplet = new Button(siOptionsComposite, SWT.RADIO);
		clientApplet.setText("Client Applet");
		clientApplet.setEnabled(false);
		clientApplet.setLayoutData(span1);
		clientApplet.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				serverClientSelected(e);
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				serverClientSelected(e);
			}
		});

		// place holder
		new Label(siOptionsComposite, SWT.LEFT).setLayoutData(span1);
		new Label(siOptionsComposite, SWT.LEFT).setLayoutData(span1);

		// label
		siNameLabel = new Label(composite, SWT.LEFT);
		siNameLabel.setText("Shareable interface name:");
		siNameLabel.setEnabled(false);

		// text
		siName = new Text(composite, SWT.BORDER | SWT.SINGLE);
		siName.setEnabled(false);
		siName.setLayoutData(span1);
		siName.addModifyListener(new ModifyListener() {
			@Override
			public void modifyText(ModifyEvent e) {
				validatePage();
			}
		});

		// label
		siImplNameLabel = new Label(composite, SWT.LEFT);
		siImplNameLabel.setText("Shareable interface implementer name:");
		siImplNameLabel.setEnabled(false);

		// text
		siImplName = new Text(composite, SWT.BORDER | SWT.SINGLE);
		siImplName.setEnabled(false);
		siImplName.setLayoutData(span1);
		siImplName.addModifyListener(new ModifyListener() {
			@Override
			public void modifyText(ModifyEvent e) {
				validatePage();
			}
		});

		// place holder
		new Label(composite, SWT.LEFT).setLayoutData(span1);

		// checkbox
		generateSISampleCode = new Button(composite, SWT.CHECK);
		generateSISampleCode.setText("Generate sample code");
		generateSISampleCode.setLayoutData(span1);
		generateSISampleCode.setEnabled(false);
		generateSISampleCode.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				generateSISampleCodeSelected(e);
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				generateSISampleCodeSelected(e);
			}
		});

		setControl(composite);

		Dialog.applyDialogFont(composite);

	}

	protected void supportsRMISelected(SelectionEvent e) {
		if (this.supportsRMI.getSelection()) {
			this.riNameLabel.setEnabled(true);
			this.riName.setEnabled(true);
			this.riImplNameLabel.setEnabled(true);
			this.riImplName.setEnabled(true);
			this.generateRMISampleCode.setEnabled(true);

			String packageName = this.newJCAppletWizardPage.getPackageFragment().getElementName();
			String typeName = this.newJCAppletWizardPage.getTypeName();
			if (this.riName.getText() == null || this.riName.getText().equals("")) {
				this.riName.setText(packageName + "." + typeName + "RI");
			}
			if (this.riImplName.getText() == null || this.riImplName.getText().equals("")) {
				this.riImplName.setText(packageName + "." + typeName + "RIImpl");
			}
		} else {
			this.riNameLabel.setEnabled(false);
			this.riName.setEnabled(false);
			this.riImplNameLabel.setEnabled(false);
			this.riImplName.setEnabled(false);
			this.generateRMISampleCode.setEnabled(false);
		}
		validatePage();
	}

	protected void generateRMISampleCodeSelected(SelectionEvent e) {
		updateBean();
	}

	protected void supportsSISelected(SelectionEvent e) {
		if (this.supportsSI.getSelection()) {
			this.serverApplet.setEnabled(true);
			this.clientApplet.setEnabled(true);
		} else {
			this.serverApplet.setEnabled(false);
			this.clientApplet.setEnabled(false);
		}
		serverClientSelected(e);
		validatePage();
	}

	protected void serverClientSelected(SelectionEvent e) {
		if (this.supportsSI.getSelection() && this.serverApplet.getSelection()) {
			this.siNameLabel.setEnabled(true);
			this.siName.setEnabled(true);
			this.siImplNameLabel.setEnabled(true);
			this.siImplName.setEnabled(true);
			this.generateSISampleCode.setEnabled(true);

			String packageName = this.newJCAppletWizardPage.getPackageFragment().getElementName();
			String typeName = this.newJCAppletWizardPage.getTypeName();
			if (this.siName.getText() == null || this.siName.getText().equals("")) {
				this.siName.setText(packageName + "." + typeName + "SI");
			}
			if (this.siImplName.getText() == null || this.siImplName.getText().equals("")) {
				this.siImplName.setText(packageName + "." + typeName + "SIImpl");
			}
		} else {
			this.siNameLabel.setEnabled(false);
			this.siName.setEnabled(false);
			this.siImplNameLabel.setEnabled(false);
			this.siImplName.setEnabled(false);
			this.generateSISampleCode.setEnabled(false);
		}
		validatePage();
	}

	protected void generateSISampleCodeSelected(SelectionEvent e) {
		updateBean();
	}

	protected void validatePage() {
		setErrorMessage(null);
		setMessage(null, IMessageProvider.WARNING);
		setPageComplete(false);
		if (this.supportsRMI.getSelection()) {
			if (!validateTypeName(this.riName.getText())) {
				return;
			}
			if (!validateTypeExistence(this.riName.getText())) {
				return;
			}
			if (this.riImplName.getText() != null && !this.riImplName.getText().equals("")) {
				if (!validateTypeName(this.riImplName.getText())) {
					return;
				}
				if (!validateTypeExistence(this.riImplName.getText())) {
					return;
				}
			}
		}

		if (this.supportsSI.getSelection()) {
			if (this.serverApplet.getSelection()) {
				if (!validateTypeName(this.siName.getText())) {
					return;
				}
				if (!validateTypeExistence(this.siName.getText())) {
					return;
				}
				if (this.siImplName.getText() != null && !this.siImplName.getText().equals("")) {
					if (!validateTypeName(this.siImplName.getText())) {
						return;
					}
					if (!validateTypeExistence(this.siImplName.getText())) {
						return;
					}
				}
			}
		}
		setPageComplete(true);
		updateBean();
	}

	protected boolean validateTypeName(String typeName) {
		if (typeName == null || typeName.equals("")) {
			return false;
		}

		// validate java type name
		IStatus status = JavaConventions.validateJavaTypeName(typeName);
		if (status.getSeverity() == IStatus.ERROR) {
			setErrorMessage(status.getMessage());
			return false;
		} else if (status.getSeverity() == IStatus.WARNING) {
			setMessage(status.getMessage(), IMessageProvider.WARNING);
		}

		// validate package name
		String packageName = extractPackageName(typeName);
		status = JavaConventions.validatePackageName(packageName);
		if (status.getSeverity() == IStatus.ERROR) {
			setErrorMessage(status.getMessage());
			return false;
		} else if (status.getSeverity() == IStatus.WARNING) {
			setMessage(status.getMessage(), IMessageProvider.WARNING);
		}

		return true;
	}

	protected boolean validateTypeExistence(String typeName) {
		if (typeName == null || typeName.equals("")) {
			return false;
		}

		try {
			IType type = this.newJCAppletWizardPage.getPackageFragmentRoot().getJavaProject().findType(typeName);
			if (type != null) {
				setErrorMessage("Type already exists.");
				return false;
			}
			return true;
		} catch (JavaModelException e) {
			setErrorMessage(e.getMessage());
			MessageDialog.openError(getShell(), "Error", e.getMessage());
		}
		return false;
	}

	public void createRIType(IProgressMonitor monitor) throws CoreException, InterruptedException {
		// validations
		if (this.bean == null || !this.bean.isSupportsRMI()) {
			return;
		}
		IType jcApplet = this.newJCAppletWizardPage.getCreatedType();
		if (jcApplet == null) {
			this.newJCAppletWizardPage.createType(monitor);
		}

		// extract package name
		String packageName = extractPackageName(this.bean.getRiName());
		String riName = extractSimpleJavaTypeName(this.bean.getRiName());

		// create package
		IPackageFragmentRoot packFragRoot = this.newJCAppletWizardPage.getPackageFragmentRoot();
		IPackageFragment packFrag = packFragRoot.createPackageFragment(packageName, true, monitor);

		// create interface
		NewInterfaceWizardPage interfaceUtil = new NewInterfaceWizardPage();
		interfaceUtil.setPackageFragment(packFrag, true);
		interfaceUtil.setTypeName(riName, true);
		ArrayList superInterfaceList = new ArrayList();
		superInterfaceList.add("java.rmi.Remote");
		interfaceUtil.setSuperInterfaces(superInterfaceList, true);
		interfaceUtil.createType(monitor);
		createdRIType = interfaceUtil.getCreatedType();

		// generate code
		if (this.bean.isGenerateRMISampleCode()) {
			monitor.setTaskName("generating remote interface code");
			generateRITypeSampleCode(monitor);
		}
	}

	public void createRIImplType(IProgressMonitor monitor) throws CoreException, InterruptedException {
		// validations
		if (this.bean == null || !this.bean.isSupportsRMI()) {
			return;
		}
		if (this.bean.getRiImplName() == null || this.bean.getRiImplName().equals("")) {
			return;
		}
		if (createdRIType == null) {
			createRIType(monitor);
		}

		// extract package name
		String packageName = extractPackageName(this.bean.getRiImplName());
		String riImplName = extractSimpleJavaTypeName(this.bean.getRiImplName());

		// create package
		IPackageFragmentRoot packFragRoot = this.newJCAppletWizardPage.getPackageFragmentRoot();
		IPackageFragment packFrag = packFragRoot.createPackageFragment(packageName, true, monitor);

		// create class
		NewClassWizardPage classUtil = new NewClassWizardPage();
		classUtil.setPackageFragment(packFrag, true);
		classUtil.setTypeName(riImplName, true);
		classUtil.setSuperClass("javacard.framework.service.CardRemoteObject", true);
		ArrayList superInterfaceList = new ArrayList();
		superInterfaceList.add(createdRIType.getFullyQualifiedName());
		classUtil.setSuperInterfaces(superInterfaceList, true);
		classUtil.setMethodStubSelection(false, true, true, true);
		classUtil.createType(monitor);
		createdRIImplType = classUtil.getCreatedType();

		// updating constructor
		StringBuffer content = new StringBuffer();
		IMethod constructor = createdRIImplType.getMethod(createdRIImplType.getElementName(), new String[] {});
		if (constructor != null && constructor.exists()) {
			content = new StringBuffer(constructor.getSource());
			content.insert(content.lastIndexOf("}"), "\tsuper();\n");
			constructor.delete(true, monitor);
		} else {
			content.append("public " + createdRIImplType.getElementName() + "() {\n");
			content.append("\tsuper();\n");
			content.append("}");
		}
		IStatus status = JCDECore.formatMethodCode(content.toString(), createdRIImplType.getJavaProject());
		if (status.getSeverity() == IStatus.OK) {
			createdRIImplType.createMethod(status.getMessage(), null, true, monitor);
		} else {
			createdRIImplType.createMethod(content.toString(), null, true, monitor);
		}

		// generate code
		if (this.bean.isGenerateRMISampleCode()) {
			monitor.setTaskName("generating remote interface implementer code");
			generateRIImplTypeSampleCode(monitor);
		}
	}

	public void createSIType(IProgressMonitor monitor) throws CoreException, InterruptedException {
		// validations
		if (this.bean == null || !(this.bean.isSupportsSI() && this.bean.isServerApplet())) {
			return;
		}
		IType jcApplet = this.newJCAppletWizardPage.getCreatedType();
		if (jcApplet == null) {
			this.newJCAppletWizardPage.createType(monitor);
		}

		// extract package name
		String packageName = extractPackageName(this.bean.getSiName());
		String siName = extractSimpleJavaTypeName(this.bean.getSiName());

		// create package
		IPackageFragmentRoot packFragRoot = this.newJCAppletWizardPage.getPackageFragmentRoot();
		IPackageFragment packFrag = packFragRoot.createPackageFragment(packageName, true, monitor);

		// create interface
		NewInterfaceWizardPage interfaceUtil = new NewInterfaceWizardPage();
		interfaceUtil.setPackageFragment(packFrag, true);
		interfaceUtil.setTypeName(siName, true);
		ArrayList superInterfaceList = new ArrayList();
		superInterfaceList.add("javacard.framework.Shareable");
		interfaceUtil.setSuperInterfaces(superInterfaceList, true);
		interfaceUtil.createType(monitor);
		createdSIType = interfaceUtil.getCreatedType();

		// generate code
		if (this.bean.isGenerateSISampleCode()) {
			monitor.setTaskName("generating shareable interface code");
			generateSITypeSampleCode(monitor);
		}
	}

	public void createSIImplType(IProgressMonitor monitor) throws CoreException, InterruptedException {
		// validations
		if (this.bean == null || !(this.bean.isSupportsSI() && this.bean.isServerApplet())) {
			return;
		}
		if (this.bean.getSiImplName() == null || this.bean.getSiImplName().equals("")) {
			return;
		}
		if (createdSIType == null) {
			createSIType(monitor);
		}

		// extract package name
		String packageName = extractPackageName(this.bean.getSiImplName());
		String siImplName = extractSimpleJavaTypeName(this.bean.getSiImplName());

		// create package
		IPackageFragmentRoot packFragRoot = this.newJCAppletWizardPage.getPackageFragmentRoot();
		IPackageFragment packFrag = packFragRoot.createPackageFragment(packageName, true, monitor);

		// create class
		NewClassWizardPage classUtil = new NewClassWizardPage();
		classUtil.setPackageFragment(packFrag, true);
		classUtil.setTypeName(siImplName, true);
		ArrayList superInterfaceList = new ArrayList();
		superInterfaceList.add(createdSIType.getFullyQualifiedName());
		classUtil.setSuperInterfaces(superInterfaceList, true);
		classUtil.setMethodStubSelection(false, true, true, true);
		classUtil.createType(monitor);
		createdSIImplType = classUtil.getCreatedType();

		// generate code
		if (this.bean.isGenerateSISampleCode()) {
			monitor.setTaskName("generating shareable interface implementer code");
			generateSIImplTypeSampleCode(monitor);
		}
	}

	public void createExtraFeatures(IProgressMonitor monitor) throws CoreException, InterruptedException {
		createRIType(monitor);
		createRIImplType(monitor);
		createSIType(monitor);
		createSIImplType(monitor);
	}

	protected String extractPackageName(String fullyQualifiedName) {
		String packageName = "";
		if (fullyQualifiedName.indexOf('.') > -1) {
			int lastIndex = fullyQualifiedName.lastIndexOf('.');
			packageName = fullyQualifiedName.substring(0, lastIndex);
		}
		return packageName;
	}

	protected String extractSimpleJavaTypeName(String fullyQualifiedName) {
		String simpleJavaTypeName = fullyQualifiedName;
		if (fullyQualifiedName.indexOf('.') > -1) {
			int lastIndex = fullyQualifiedName.lastIndexOf('.');
			simpleJavaTypeName = simpleJavaTypeName.substring(lastIndex + 1, simpleJavaTypeName.length());
		}
		return simpleJavaTypeName;
	}

	public void generateRITypeSampleCode(IProgressMonitor monitor) throws CoreException {
		// adding imports
		createdRIType.getCompilationUnit().createImport("java.rmi.RemoteException", null, monitor);

		// adding sampleMethod() method
		StringBuffer content = new StringBuffer("");
		content.append("public short sampleMethod() throws RemoteException;");
		IStatus status = JCDECore.formatMethodCode(content.toString(), createdRIType.getJavaProject());
		if (status.getSeverity() == IStatus.OK) {
			createdRIType.createMethod(status.getMessage(), null, true, monitor);
		} else {
			createdRIType.createMethod(content.toString(), null, true, monitor);
		}
	}

	public void generateRIImplTypeSampleCode(IProgressMonitor monitor) throws CoreException {
		IType createdType = this.newJCAppletWizardPage.getCreatedType();

		// adding imports
		createdType.getCompilationUnit().createImport("javacard.framework.service.Dispatcher", null, monitor);
		createdType.getCompilationUnit().createImport("javacard.framework.service.RMIService", null, monitor);
		createdType.getCompilationUnit().createImport(createdRIImplType.getPackageFragment().getElementName() + "." + createdRIImplType.getElementName(), null, monitor);
		createdType.getCompilationUnit().createImport("javacard.framework.APDU", null, monitor);
		createdType.getCompilationUnit().createImport("javacard.framework.ISOException", null, monitor);

		createdRIImplType.getCompilationUnit().createImport("java.rmi.RemoteException", null, monitor);

		// adding sample method
		StringBuffer content = new StringBuffer("");
		IMethod sampleMethod = createdRIImplType.getMethod("sampleMethod", new String[] {});
		if (sampleMethod == null || !sampleMethod.exists()) {
			content.append("public short sampleMethod() throws RemoteException {\n");
			content.append("\treturn 0;\n");
			content.append("}");
			IStatus status = JCDECore.formatMethodCode(content.toString(), createdRIImplType.getJavaProject());
			if (status.getSeverity() == IStatus.OK) {
				createdRIImplType.createMethod(status.getMessage(), null, true, monitor);
			} else {
				createdRIImplType.createMethod(content.toString(), null, true, monitor);
			}
		}

		// updating Applet code

		// adding Dispatcher field
		content = new StringBuffer("");
		content.append("private Dispatcher dispatcher;");
		createdType.createField(content.toString(), null, true, monitor);

		// updating contructor
		IMethod constructor = createdType.getMethod(createdType.getElementName(), new String[] {});
		if (constructor != null && constructor.exists()) {
			content = new StringBuffer(constructor.getSource());
			content.insert(content.lastIndexOf("}"), "\tRMIService rmiService = new RMIService(new " + createdRIImplType.getElementName() + "());\n");
			content.insert(content.lastIndexOf("}"), "\tdispatcher = new Dispatcher((short) 1);\n");
			content.insert(content.lastIndexOf("}"), "\tdispatcher.addService(rmiService, Dispatcher.PROCESS_COMMAND);\n");
			constructor.delete(true, monitor);
		} else {
			content = new StringBuffer();
			content.append("private " + createdType.getElementName() + "() {\n");
			content.append("\tRMIService rmiService = new RMIService(new " + createdRIImplType.getElementName() + "());\n");
			content.append("\tdispatcher = new Dispatcher((short) 1);\n");
			content.append("\tdispatcher.addService(rmiService, Dispatcher.PROCESS_COMMAND);\n");
			content.append("}");
		}
		IMethod[] methods = createdType.getMethods();
		IJavaElement sibling = null;
		if (methods.length > 0) {
			sibling = methods[0];
		}
		IStatus status = JCDECore.formatMethodCode(content.toString(), createdType.getJavaProject());
		if (status.getSeverity() == IStatus.OK) {
			createdType.createMethod(status.getMessage(), sibling, true, monitor);
		} else {
			createdType.createMethod(content.toString(), sibling, true, monitor);
		}

		// updating process() method
		IMethod processMethod = createdType.getMethod("process", new String[] { "Qjavacard.framework.APDU;" });
		if (processMethod == null || !processMethod.exists()) {
			processMethod = createdType.getMethod("process", new String[] { "QAPDU;" });
		}
		if (processMethod != null && processMethod.exists()) {
			processMethod.delete(true, monitor);
		}
		content = new StringBuffer();
		content.append("public void process(APDU command) throws ISOException {\n");
		content.append("\tdispatcher.process(command);\n");
		content.append("}");
		status = JCDECore.formatMethodCode(content.toString(), createdType.getJavaProject());
		if (status.getSeverity() == IStatus.OK) {
			createdType.createMethod(status.getMessage(), null, true, monitor);
		} else {
			createdType.createMethod(content.toString(), null, true, monitor);
		}
	}

	public void generateSITypeSampleCode(IProgressMonitor monitor) throws CoreException {
		// adding sampleMethod() method
		StringBuffer content = new StringBuffer("");
		content.append("public short sampleMethod();");
		IStatus status = JCDECore.formatMethodCode(content.toString(), createdSIType.getJavaProject());
		if (status.getSeverity() == IStatus.OK) {
			createdSIType.createMethod(status.getMessage(), null, true, monitor);
		} else {
			createdSIType.createMethod(content.toString(), null, true, monitor);
		}
	}

	public void generateSIImplTypeSampleCode(IProgressMonitor monitor) throws CoreException {
		IType createdType = this.newJCAppletWizardPage.getCreatedType();

		// adding imports
		createdType.getCompilationUnit().createImport(createdSIType.getPackageFragment().getElementName() + "." + createdSIType.getElementName(), null, monitor);
		createdType.getCompilationUnit().createImport(createdSIImplType.getPackageFragment().getElementName() + "." + createdSIImplType.getElementName(), null, monitor);
		createdType.getCompilationUnit().createImport("javacard.framework.Shareable", null, monitor);
		createdType.getCompilationUnit().createImport("javacard.framework.AID", null, monitor);

		// adding sampleMethod() method
		StringBuffer content = new StringBuffer("");
		IMethod sampleMethod = createdSIImplType.getMethod("sampleMethod", new String[] {});
		if (sampleMethod == null && !sampleMethod.exists()) {
			content.append("public short sampleMethod() {\n");
			content.append("\treturn 0;\n");
			content.append("}");
			IStatus status = JCDECore.formatMethodCode(content.toString(), createdSIImplType.getJavaProject());
			if (status.getSeverity() == IStatus.OK) {
				createdSIImplType.createMethod(status.getMessage(), null, true, monitor);
			} else {
				createdSIImplType.createMethod(content.toString(), null, true, monitor);
			}
		}

		// updating Applet code

		// adding SI field
		content = new StringBuffer("");
		content.append("private " + createdSIType.getElementName() + " sio;");
		createdType.createField(content.toString(), null, true, monitor);

		// updating constructor
		IMethod constructor = createdType.getMethod(createdType.getElementName(), new String[] {});
		if (constructor != null && constructor.exists()) {
			content = new StringBuffer(constructor.getSource());
			content.insert(content.lastIndexOf("}"), "\tsio = new " + createdSIImplType.getElementName() + "();\n");
			constructor.delete(true, monitor);
		} else {
			content = new StringBuffer();
			content.append("private " + createdType.getElementName() + "() {\n");
			content.append("\tsio = new " + createdSIImplType.getElementName() + "();\n");
			content.append("}");
		}
		IMethod[] methods = createdType.getMethods();
		IJavaElement sibling = null;
		if (methods.length > 0) {
			sibling = methods[0];
		}
		IStatus status = JCDECore.formatMethodCode(content.toString(), createdType.getJavaProject());
		if (status.getSeverity() == IStatus.OK) {
			createdType.createMethod(status.getMessage(), sibling, true, monitor);
		} else {
			createdType.createMethod(content.toString(), sibling, true, monitor);
			if (status.getSeverity() == IStatus.ERROR) {
				throw new CoreException(status);
			}
		}

		// adding getShareableInterfaceObject() method
		content = new StringBuffer();
		content.append("public Shareable getShareableInterfaceObject(AID clientAID, byte parameter) {\n");
		content.append("\treturn sio;\n");
		content.append("}");
		status = JCDECore.formatMethodCode(content.toString(), createdType.getJavaProject());
		if (status.getSeverity() == IStatus.OK) {
			createdType.createMethod(status.getMessage(), null, true, monitor);
		} else {
			createdType.createMethod(content.toString(), null, true, monitor);
			if (status.getSeverity() == IStatus.ERROR) {
				throw new CoreException(status);
			}
		}
	}

	protected void updateBean() {
		if (this.bean == null) {
			this.bean = new ExtraFeaturesBean();
		}

		this.bean.setSupportsRMI(this.isSupportsRMI());
		this.bean.setRiName(this.getRiName());
		this.bean.setRiImplName(this.getRiImplName());
		this.bean.setGenerateRMISampleCode(this.isGenerateRMISampleCode());
		this.bean.setSupportsSI(this.isSupportsSI());
		this.bean.setServerApplet(this.isServerApplet());
		this.bean.setClientApplet(this.isClientApplet());
		this.bean.setSiName(this.getSiName());
		this.bean.setSiImplName(this.getSiImplName());
		this.bean.setGenerateSISampleCode(this.isGenerateSISampleCode());
	}

	protected class ExtraFeaturesBean {
		private boolean supportsRMI;

		private String riName;

		private String riImplName;

		private boolean generateRMISampleCode;

		private boolean supportsSI;

		private boolean serverApplet;

		private boolean clientApplet;

		private String siName;

		private String siImplName;

		private boolean generateSISampleCode;

		public boolean isClientApplet() {
			return clientApplet;
		}

		public void setClientApplet(boolean clientApplet) {
			this.clientApplet = clientApplet;
		}

		public boolean isGenerateRMISampleCode() {
			return generateRMISampleCode;
		}

		public void setGenerateRMISampleCode(boolean generateRMISampleCode) {
			this.generateRMISampleCode = generateRMISampleCode;
		}

		public boolean isGenerateSISampleCode() {
			return generateSISampleCode;
		}

		public void setGenerateSISampleCode(boolean generateSISampleCode) {
			this.generateSISampleCode = generateSISampleCode;
		}

		public String getRiImplName() {
			return riImplName;
		}

		public void setRiImplName(String riImplName) {
			this.riImplName = riImplName;
		}

		public String getRiName() {
			return riName;
		}

		public void setRiName(String riName) {
			this.riName = riName;
		}

		public boolean isServerApplet() {
			return serverApplet;
		}

		public void setServerApplet(boolean serverApplet) {
			this.serverApplet = serverApplet;
		}

		public String getSiImplName() {
			return siImplName;
		}

		public void setSiImplName(String siImplName) {
			this.siImplName = siImplName;
		}

		public String getSiName() {
			return siName;
		}

		public void setSiName(String siName) {
			this.siName = siName;
		}

		public boolean isSupportsRMI() {
			return supportsRMI;
		}

		public void setSupportsRMI(boolean supportsRMI) {
			this.supportsRMI = supportsRMI;
		}

		public boolean isSupportsSI() {
			return supportsSI;
		}

		public void setSupportsSI(boolean supportsSI) {
			this.supportsSI = supportsSI;
		}
	}

}
